#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#define SIZE 128
#define NUM 32
#define DELIM " "

char *Argv[NUM];
char pwd[SIZE*2];
int exit_code;
void CommandLine()
{
    char CommandLine[SIZE];
    const char* UserName = getenv("USER");
    const char* HostName = getenv("HOSTNAME");
    const char* Pwd = getenv("PWD");
    int pos = strlen(Pwd) - 1;
    while (Pwd[pos] != '/') pos--;
    Pwd = Pwd + pos;
    sprintf(CommandLine,"[%s@%s %s]> ", UserName, HostName, Pwd);
    printf("%s", CommandLine);
    fflush(stdout);
}

int  ReadUserCommand(char Buffer[], size_t size)
{
    char *ret = fgets(Buffer, size, stdin);
    if (ret == NULL) return -1;
    Buffer[strlen(Buffer) - 1] = '\0';
    return strlen(Buffer);
}
void SplitUserCommand(char Buffer[])
{
    Argv[0] = strtok(Buffer, DELIM);
    int index = 1;
    while ((Argv[index++] = strtok(NULL, DELIM)));
}
void ExcuteCommand()
{
    pid_t id = fork();
    if (id == 0)
    {
        //child
        execvp(Argv[0], Argv);
        exit(errno);
    }
    else if (id > 0)
    {
        //parent
        int status = 0;
        pid_t rid = waitpid(id, &status, 0);
        if (rid > 0)
        {
            if (!WIFEXITED(status))
            {
                exit_code = WEXITSTATUS(status);
                if (exit_code != 0)
                {
                    printf("-shell:%s:%s\n", Argv[0], strerror(exit_code));
                }
            }
        }
    }
    else 
    {
        exit(1);
    }
}

int CheckCommand()
{
    int ret = 0;
    if (strcmp(Argv[0], "cd") == 0)
    {
        ret = 1;
        char* path = Argv[1];
        if (path == NULL) path = getenv("HOME");
        //更改当前进程的工作目录 
        chdir(path);
        //刷新环境变量
        char tmp[SIZE*2];
        getcwd(tmp, sizeof tmp);
        snprintf(pwd, sizeof(pwd), "PWD=%s", tmp);
        putenv(pwd);
    }
    return ret;
}

int main()
{
    while (1)
    {

        //1. 打印命令行提示
        CommandLine();
        //2. 读取用户输入的命令
        char Buffer[SIZE];
        int ret =  ReadUserCommand(Buffer, sizeof(Buffer));
        if (ret < 0) return 1;
        else if(ret == 0) continue;
        //3. 解析命令
        SplitUserCommand(Buffer);
        //4. 判断是否是内键命令
        CheckCommand();
        //5. 执行命令
        ExcuteCommand();
    }
    return 0;
}
